/*************************************************************************************
 * Nombre del archivo: Generador_Analizador_lexico.java
 * Universidad del Valle de Guatemala
 * Curso: Diseño de Lenguajes de Programación
 * @author martin
 *          Martín Guzmán 08041
 * Fecha: Abril de 2010
 * Descripción: Generador de analizador léxico
*************************************************************************************/

import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;

public class DefCocol {

    //--------------------------------------------------------------------------
    //##########################################################################
        // ------- vocabulario de cocol ----------------------------------------
        static String letter="[a-zA-Z]";
        static String digit="\\d";
        static String number=digit+"("+digit+")*";
        static String ident=letter+"("+letter+"|"+digit+")*";
        static String string="\""+"("+number+"|"+letter+"|[^\\\"])*"+"\"";
        static String character="\'"+"("+number+"|"+letter+"|[^\\\'])"+"\'";
        static String space="(\\s)*";
        // ---------------------------------------------------------------------
        static int contador_token_parsers = 1;
        static LinkedList<String> tokens_en_parser = new LinkedList<String>();
        static LinkedList<String> tokens = new LinkedList<String>();
    //##########################################################################
    
    /***********************************************
     * Método: Generador_Analizador_Lexico
     * Uso: Constructor
     * @param file_lines
     * @param path contiene la carpeta en donde se creará el generador
    ***********************************************/
    public DefCocol() {}

    /***********************************************
     * Método: Complementar_cadena
     * Uso: Corta la cadena hasta el índice i
     * @param a contiene el índice hasta donde cortar
     * @param cadena contiene la cadena a cortar
    ***********************************************/
    public static String Complementar_cadena(String cadena, int a){
        try{
            String cadena2 = "";
            cadena2 = cadena.substring(a);
            //Main.PrintDB("Cadena cortada: "+cadena2);
            return cadena2;
        }catch(Exception exp){
            Main.PrintDB("Error al copiar cortar la cadena: "+cadena+" en el índice: "+a);
        }
        return "";

    }

    /***********************************************
     * Método: Revisar_Palabras_Reservadas
     * Uso: Revisa  que no se haga un método con el nombre
     *      de una palabra reservada
     * @param cadena a revisar
     * @return String con la cadena
    ***********************************************/
    public static String Revisar_Palabras_Reservadas(String cadena){
        LinkedList<String> palabras = new LinkedList<String>();

        palabras.add("do");
        palabras.add("true");
        palabras.add("false");
        palabras.add("new");
        palabras.add("while");
        palabras.add("if");
        palabras.add("switch");
        palabras.add("case");
        palabras.add("try");
        palabras.add("catch");
        palabras.add("int");
        palabras.add("double");
        palabras.add("boolean");
        palabras.add("char");
        palabras.add("public");
        palabras.add("continue");
        palabras.add("private");
        palabras.add("static");
        palabras.add("void");
        palabras.add("return");

        if(palabras.contains(cadena)==true){
            return cadena+"_0";
        }

        return cadena;
    }

    /***********************************************
     * Método: Revisar_Palabras_Reservadas
     * Uso: Revisa  que no se haga un método con el nombre
     *      de una palabra reservada
     * @param cadena a revisar
     * @return String con la cadena
    ***********************************************/
    public static boolean is_Palabra_Reservada(String cadena){
        if(DefCocol.Revisar_Palabras_Reservadas(cadena).compareTo(cadena)==0){
            return false;
        }
        return true;
    }

    /***********************************************
     * Método: expect
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de cocol
     * @param regex contiene la regex con la que hay que evaluar
     * @param cadena que hay que revisar que haga match
     * @return int con el índice hasta donde hizo match o -1 si no hizo match
    ***********************************************/
    public static Retorno_Funcion expect(String regex, String cadena) {

        String cadena_encontrada="";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(cadena);

        if (matcher.find()) {
            cadena_encontrada=matcher.group();
            //Main.Print("Encontrado: \""+cadena_encontrada+"\"");// entre ["+index_begin+","+index_end+"]");
            if(matcher.start()==0){
                Retorno_Funcion ret = new Retorno_Funcion();
                ret.indice=matcher.end();
                ret.aceptado=true;
                ret.cadena=cadena_encontrada;
                return ret;
            }
        }
        return (new Retorno_Funcion());
    }

    /***********************************************
     * Método: Char
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de BasicSet
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Char(String cadena) {
        // Char = character | "CHR" '(' number ')'
        //------------------------------------------
        // Char = character
        if(DefCocol.expect(DefCocol.character, cadena).aceptado==true){
            Retorno_Funcion retorno = new Retorno_Funcion();
            retorno.indice = DefCocol.expect(DefCocol.character, cadena).indice;
            retorno.aceptado = true;
            retorno.cadena = DefCocol.expect(DefCocol.character, cadena).cadena;
            return  retorno;
        }
        //------------------------------------------
        // "CHR" '(' number ')'
        if(DefCocol.expect("CHR\\("+DefCocol.number+"\\)", cadena).aceptado==true){
            Retorno_Funcion retorno = new Retorno_Funcion();
            retorno.indice = DefCocol.expect("CHR\\("+DefCocol.number+"\\)", cadena).indice;
            retorno.aceptado = true;
            retorno.cadena = DefCocol.expect("CHR\\("+DefCocol.number+"\\)", cadena).cadena;
            return  retorno;
        }
        //------------------------------------------
        return (new Retorno_Funcion());
    }

    /***********************************************
     * Método: BasicSet
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de BasicSet
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion BasicSet(String cadena) {
        Main.PrintDB(">> cadena que entra al BasicSet: "+cadena);
        // BasicSet = string | ident | Char [".." Char ]
        LinkedList<String> cadenas_encontradas = new LinkedList<String>();
        //------------------------------------------
        // BasicSet = string
        if(DefCocol.expect(DefCocol.string, cadena).aceptado==true){
            cadenas_encontradas.add(DefCocol.expect(DefCocol.string, cadena).cadena);
        }
        //------------------------------------------
        // BasicSet = ident
        if(DefCocol.expect(DefCocol.ident, cadena).aceptado==true){
            cadenas_encontradas.add(DefCocol.expect(DefCocol.ident, cadena).cadena);
        }
        //------------------------------------------
        // BasicSet = Char [".." Char ]
        // -- Char --------------
        Retorno_Funcion ret2 = DefCocol.Char_BasicSet(cadena);
        if(ret2.aceptado==true){
            cadenas_encontradas.add(ret2.cadena);
        }

        if(cadenas_encontradas.size()==0){
            return (new Retorno_Funcion());
        }
        Main.PrintDB(">> las cadenas que encontró: "+cadenas_encontradas);
        Collections.sort(cadenas_encontradas, new Comparator<String>() {
            public int compare(String o1, String o2) {
                Integer a1 = o1.length();
                Integer a2 = o2.length();
                return a2-a1;
            }
        });
        //Main.Print(cadenas_encontradas.toString());
        Retorno_Funcion retorno = new Retorno_Funcion();
        retorno.aceptado=true;
        retorno.indice=cadenas_encontradas.getFirst().length();
        retorno.cadena=cadenas_encontradas.getFirst();
        return retorno;
    }

    /***********************************************
     * Método: Char_BasicSet
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de Char_BasicSet (Char[..Char])
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Char_BasicSet(String cadena) {
        // Char[..Char]
        String cadena1 = cadena;

        Retorno_Funcion ret1 = DefCocol.Char(cadena1);
        if(ret1.aceptado==false){
            return new Retorno_Funcion();
        }
        Main.PrintDB("CharBasicSet "+"tiene BasicSet: "+ret1.cadena);

        cadena1 = DefCocol.Complementar_cadena(cadena1, ret1.indice);
        Retorno_Funcion ret2 = DefCocol.expect("\\.\\.", cadena1);

        if(ret2.aceptado==false){
            Main.PrintDB("-----------------------------------------------------------");
            return ret1;
        }
        Main.PrintDB("CharBasicSet "+"tiene ..: "+ret2.cadena);
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret2.indice);
        Retorno_Funcion ret3 = DefCocol.Char(cadena1);

        if(ret3.aceptado==false){
            
            return ret1;
        }
        Main.PrintDB("CharBasicSet "+"tiene BasicSet: "+ret3.cadena);
        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1.cadena + ret2.cadena + ret3.cadena;
        ret.indice = ret1.indice + ret2.indice + ret3.indice;
        return ret;
    }

    /***********************************************
     * Método: Set
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de Set
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Set(String cadena) {
        // Set = BasicSet { ('+'|'-') BasicSet }
        //------------------------------------------
        // Set = BasicSet
        Retorno_Funcion ret = DefCocol.BasicSet(cadena);
        if(ret.aceptado==false){
            //ya no puede ser aceptado porque no empieza con un BasicSet
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret.indice);
        //------------------------------------------
        // { ('+'|'-') BasicSet }
        while(true){
            //Main.PrintDB(cadena1);
            //('+'|'-')
            Retorno_Funcion bool = DefCocol.expect(DefCocol.space+"(\\+|\\-)"+DefCocol.space, cadena1);

            if(bool.aceptado == false){
                //no tiene ni + ni -, entonces se sale del *
                //Main.Print("aca termino (no tiene +-)");
                break;
            }

            cadena1 = DefCocol.Complementar_cadena(cadena1, bool.indice);

            //BasicSet
            Retorno_Funcion b = DefCocol.BasicSet(cadena1);
            if(b.aceptado==false){
                //Main.Print("aca termino (no tiene BasicSet)");
                //no hay BasicSet, entonces se sale del *
                break;
            }
            
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret.indice = ret.indice+bool.indice+b.indice;
            ret.cadena = ret.cadena+bool.cadena+b.cadena;
        }
        Main.PrintDB(">> Set: "+ret.cadena);
        //Main.PrintDB("Cadena con la que termina: "+ret.cadena);
        return ret;
    }

    /***********************************************
     * Método: SetDecl
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de SetDecl
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion SetDecl(String cadena) {
        // SetDecl = ident '=' Set
        //Main.PrintDB("cadena en SetDecl: "+cadena);
        //------------------------------------------
        // Set = ident
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.ident, cadena);
        if(ret1.aceptado==false){
            //Main.PrintDB("No empieza con identificador");
            //ya no puede ser aceptado porque no empieza con un ident
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);
        //Main.PrintDB("cadena: "+cadena1);
        //------------------------------------------
        // '='
        Retorno_Funcion ret2 = DefCocol.expect("("+DefCocol.space+")*(=)("+DefCocol.space+")*", cadena1);
        if(ret2.aceptado==false){
            //Main.PrintDB("No tiene un '='");
            //ya no puede ser aceptado porque no tiene un '='
            return (new Retorno_Funcion());
        }
        String cadena2 = DefCocol.Complementar_cadena(cadena1, ret2.indice);
        //Main.PrintDB("cadena: "+cadena2);
        //------------------------------------------
        // Set
        Retorno_Funcion ret3 = DefCocol.Set(cadena2);
        if(ret3.aceptado==false){
            //Main.PrintDB("No tiene un Set");
            //ya no puede ser aceptado porque no tiene un Set
            return (new Retorno_Funcion());
        }
        //Main.PrintDB("cadena: si esta correcta");
        //+++++++++++++++++++++++++++++++++++++++++++++++++++
        Generador_Analizadores.Characters_SetDecl.put(Revisar_Palabras_Reservadas(ret1.cadena), ret3.cadena);
        //+++++++++++++++++++++++++++++++++++++++++++++++++++
        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1.cadena+ret2.cadena+ret3.cadena;
        ret.indice = ret1.indice+ret2.indice+ret3.indice;
        //------------------------------------------
        return ret;
    }

    /***********************************************
     * Método: KeywordDecl
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de KeywordDecl
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion KeywordDecl(String cadena) {
        // KeywordDecl = ident '=' string '.'

        //------------------------------------------
        // KeywordDecl = ident
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.ident, cadena);
        if(ret1.aceptado==false){
            //Main.PrintDB("No empieza con identificador");
            //ya no puede ser aceptado porque no empieza con un ident
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);
        //Main.PrintDB("cadena: "+cadena1);
        //------------------------------------------
        // '='
        Retorno_Funcion ret2 = DefCocol.expect("("+DefCocol.space+")(=)("+DefCocol.space+")", cadena1);
        if(ret2.aceptado==false){
            //Main.PrintDB("No tiene un '='");
            //ya no puede ser aceptado porque no tiene un '='
            return (new Retorno_Funcion());
        }
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret2.indice);
        //Main.PrintDB("cadena: "+cadena1);
        //------------------------------------------
        // string
        Retorno_Funcion ret3 = DefCocol.expect(DefCocol.string, cadena1);
        if(ret3.aceptado==false){
            //Main.PrintDB("No tiene un string");
            //ya no puede ser aceptado porque no tiene un string
            return (new Retorno_Funcion());
        }
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret3.indice);
        //Main.PrintDB("cadena: "+cadena1);
        //------------------------------------------
        // '.'
        Retorno_Funcion ret4 = DefCocol.expect("\\.", cadena1);
        if(ret4.aceptado==false){
            DefCocol.error("KeyWordDecl no termina con '.': "+cadena);
            //Main.PrintDB("No termina con '.'");
            //ya no puede ser aceptado porque no termina con un '.'
            return (new Retorno_Funcion());
        }
        Retorno_Funcion ret = new Retorno_Funcion();
        //+++++++++++++++++++++++++++++++++++++++++++++++++++
        Generador_Analizadores.Keywords_KeywordDecl.put(Revisar_Palabras_Reservadas(ret1.cadena), ret3.cadena);
        DefCocol.tokens.add(ret1.cadena);
        //+++++++++++++++++++++++++++++++++++++++++++++++++++
        ret.aceptado = true;
        ret.cadena = ret1.cadena+ret2.cadena+ret3.cadena+ret4.cadena;
        ret.indice = ret1.indice+ret2.indice+ret3.indice+ret4.indice;
        //------------------------------------------
        return ret;
    }

    /***********************************************
     * Método: Symbol
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de Symbol
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Symbol(String cadena) {
        // Symbol = ident | string | char
        //------------------------------------------
        // Symbol = ident
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.ident, cadena);
        if(ret1.aceptado==true){
            //Main.PrintDB("Symbol identificador: "+ret1.cadena);
            return ret1;
        }
        //------------------------------------------
        // Symbol = string
        ret1 = DefCocol.expect(DefCocol.string, cadena);
        if(ret1.aceptado==true){
            //Main.PrintDB("Symbol string: "+ret1.cadena);
            return ret1;
        }
        //------------------------------------------
        // Symbol = char
        ret1 = DefCocol.expect(DefCocol.character, cadena);
        if(ret1.aceptado==true){
            //Main.PrintDB("Symbol character: "+ret1.cadena);
            return ret1;
        }

        //------------------------------------------
        //si no ha hecho match significa que no es Symbol
        return (new Retorno_Funcion());
    }

    /***********************************************
     * Método: WhiteSpaceDecl
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de WhiteSpaceDecl
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion WhiteSpaceDecl(String cadena) {
        // WhiteSpaceDecl = "IGNORE" Set
        //------------------------------------------
        // Symbol = "IGNORE"
        Retorno_Funcion ret1 = DefCocol.expect("(IGNORE)"+DefCocol.space, cadena);
        if(ret1.aceptado==false){
            //Main.PrintDB("No empieza con 'IGNORE' ");
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);
        //------------------------------------------
        // Symbol = Set
        Retorno_Funcion ret2 = DefCocol.Set(cadena1);
        if(ret2.aceptado==false){
            //Main.PrintDB("No contiene un Set");
            return (new Retorno_Funcion());
        }
        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1.cadena+ret2.cadena;
        ret.indice = ret1.indice+ret2.indice;
        //------------------------------------------
        return ret;
    }

    /***********************************************
     * Método: TokenDecl
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de TokenDecl
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion TokenDecl(String cadena) {
        // TokenDecl = ident [ '=' TokenExpr ] ["EXCEPT KEYWORDS"] '.'
        //------------------------------------------
        // TokenDecl = ident
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.ident, cadena);
        if(ret1.aceptado==false){
            Main.PrintDB("TokenDecl no empieza con un ident: "+cadena);
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);
        String mapa_cadena = "";
        //------------------------------------------
        // [ '=' TokenExpr ]
                //TODO terminar TokenDecl
                Retorno_Funcion ret2 = new Retorno_Funcion(0,false,"");
                Retorno_Funcion ret21 = DefCocol.expect(DefCocol.space+"="+DefCocol.space, cadena1);
                if(ret21.aceptado==false){
                    Main.PrintDB("No tiene el '=', por lo tanto no tiene TokenExpr: "+cadena);
                }
                else{
                    String cadena2 = DefCocol.Complementar_cadena(cadena1, ret21.indice);
                    Retorno_Funcion ret22 = DefCocol.TokenExpr(cadena2);
                    if(ret22.aceptado==false){
                        Main.PrintDB("No tiene TokenExpr: "+cadena);
                    }
                    else{
                        mapa_cadena = ret22.cadena;
                        ret2.aceptado=true;
                        ret2.cadena = ret21.cadena + ret22.cadena;
                        ret2.indice = ret21.indice + ret22.indice;
                        cadena1 = DefCocol.Complementar_cadena(cadena1, ret2.indice);
                    }
                }
        //------------------------------------------
        // ["EXCEPT KEYWORDS"]
        Retorno_Funcion ret3 = DefCocol.expect(DefCocol.space+"EXCEPT KEYWORDS"+DefCocol.space, cadena1);
        if(ret3.aceptado==false){
            Main.PrintDB("TokenDecl no tiene 'EXCEPT KEYWORDS': "+cadena);
            ret3.indice=0;
        }
        else{
            if(mapa_cadena.isEmpty()){
                mapa_cadena = "EXCEPT KEYWORDS";
            }
            else{
                mapa_cadena += " EXCEPT KEYWORDS";
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret3.indice);
        }
        //------------------------------------------
        // '.'
        Retorno_Funcion ret4 = DefCocol.expect("\\.", cadena1);
        if(ret4.aceptado==false){
            //DefCocol.error("TokenDecl no termina con '.': "+cadena);
            return (new Retorno_Funcion());
        }
        //+++++++++++++++++++++++++++++++++++++++++++++++++++
        Generador_Analizadores.Tokens_TokenDecl.put(Revisar_Palabras_Reservadas(ret1.cadena), mapa_cadena);
        DefCocol.tokens.add(ret1.cadena);
        //+++++++++++++++++++++++++++++++++++++++++++++++++++
        //------------------------------------------
        //Si llegó hasta acá, ya fue aceptada
        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1.cadena+ret2.cadena+ret3.cadena+ret4.cadena;
        ret.indice = ret1.indice+ret2.indice+ret3.indice+ret4.indice;
        //------------------------------------------
        return ret;
    }

    /***********************************************
     * Método: TokenExpr
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de TokenExpr
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion TokenExpr(String cadena) {
        // TokenExpr = TokenTerm {'|' TokenTerm}
        //------------------------------------------
        // TokenTerm
        Retorno_Funcion ret1 = DefCocol.TokenTerm(cadena);
        if(ret1.aceptado==false){
            Main.PrintDB("TokenExpr no tiene tokenTerm al inicio");
            //ya no puede ser aceptado porque no empieza con un TokenTerm
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);

        //------------------------------------------
        // {'|' TokenTerm}
        Retorno_Funcion ret2 = new Retorno_Funcion(0,true,"");
        while(true){
            //Main.PrintDB(cadena1);
            //('|')
            Retorno_Funcion bool = DefCocol.expect(DefCocol.space+"(\\|)"+DefCocol.space, cadena1);
            if(bool.aceptado == false){
                //no tiene '|', entonces se sale del *
                //Main.Print("aca termino (no tiene '|')");
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, bool.indice);
            //TokenTerm
            Retorno_Funcion b = DefCocol.TokenTerm(cadena1);
            if(b.aceptado==false){
                //Main.Print("aca termino (no tiene TokenTerm)");
                //no hay BasicSet, entonces se sale del *
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret2.indice = ret2.indice+bool.indice+b.indice;
            ret2.cadena = ret2.cadena+bool.cadena+b.cadena;
        }

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1.cadena+ret2.cadena;
        ret.indice = ret1.indice+ret2.indice;
        return ret;
    }

    /***********************************************
     * Método: TokenTerm
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de TokenTerm
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion TokenTerm(String cadena) {
        // TokenTerm = TokenFactor {TokenFactor}
        //------------------------------------------
        // TokenFactor
        Retorno_Funcion ret1 = DefCocol.TokenFactor(cadena);
        if(ret1.aceptado==false){
            Main.PrintDB("TokenTerm no tiene TokenFactor al inicio: "+cadena);
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);

        //------------------------------------------
        // {TokenFactor}
        Retorno_Funcion ret2 = new Retorno_Funcion(0,true,"");
        while(true){
            //Main.PrintDB(cadena1);
            //TokenFactor
            Retorno_Funcion b = DefCocol.TokenFactor(cadena1);
            if(b.aceptado==false){
                //Main.Print("aca termino (no tiene TokenFactor)");
                //no hay BasicSet, entonces se sale del *
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret2.indice = ret2.indice+b.indice;
            ret2.cadena = ret2.cadena+b.cadena;
        }

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1.cadena+ret2.cadena;
        ret.indice = ret1.indice+ret2.indice;
        return ret;
    }

    /***********************************************
     * Método: TokenFactor
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de TokenFactor
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion TokenFactor(String cadena) {
        // TokenFactor = Symbol | '[' TokenExpr ']'| '(' TokenExpr ')'| '{' TokenExpr '}'
        //------------------------------------------
        // TokenFactor = Symbol
        Retorno_Funcion ret1 = DefCocol.Symbol(cadena);
        if(ret1.aceptado==true){
            Main.PrintDB("TokenFactor es un Symbol");
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            return ret1;
        }
        //------------------------------------------
        // TokenFactor = '[' TokenExpr ']'
        Retorno_Funcion ret2 = new Retorno_Funcion();
            Retorno_Funcion ret21 = DefCocol.expect(DefCocol.space+"\\["+DefCocol.space, cadena);
            if(ret21.aceptado==true){
                String cadena1 = DefCocol.Complementar_cadena(cadena, ret21.indice);
                Retorno_Funcion ret22 = DefCocol.TokenExpr(cadena1);
                if(ret22.aceptado==true){
                    String cadena2 = DefCocol.Complementar_cadena(cadena1, ret22.indice);
                    Retorno_Funcion ret23 = DefCocol.expect("\\]", cadena2);
                    if(ret23.aceptado==true){
                        ret2.aceptado = true;
                        ret2.cadena = ret21.cadena + ret22.cadena + ret23.cadena;
                        ret2.indice = ret21.indice + ret22.indice + ret23.indice;
                        return ret2;
                    }
                }
            }
        //------------------------------------------
        // TokenFactor = '(' TokenExpr ')'
        Retorno_Funcion ret3 = new Retorno_Funcion();
            ret21 = DefCocol.expect(DefCocol.space+"\\("+DefCocol.space, cadena);
            if(ret21.aceptado==true){
                String cadena1 = DefCocol.Complementar_cadena(cadena, ret21.indice);
                Retorno_Funcion ret22 = DefCocol.TokenExpr(cadena1);
                if(ret22.aceptado==true){
                    String cadena2 = DefCocol.Complementar_cadena(cadena1, ret22.indice);
                    Retorno_Funcion ret23 = DefCocol.expect("\\)", cadena2);
                    if(ret23.aceptado==true){
                        ret3.aceptado = true;
                        ret3.cadena = ret21.cadena + ret22.cadena + ret23.cadena;
                        ret3.indice = ret21.indice + ret22.indice + ret23.indice;
                        return ret3;
                    }
                }
            }
        //------------------------------------------
        // TokenFactor = '{' TokenExpr '}'
        Retorno_Funcion ret4 = new Retorno_Funcion();
            ret21 = DefCocol.expect(DefCocol.space+"\\{"+DefCocol.space, cadena);
            if(ret21.aceptado==true){
                String cadena1 = DefCocol.Complementar_cadena(cadena, ret21.indice);
                Retorno_Funcion ret22 = DefCocol.TokenExpr(cadena1);
                if(ret22.aceptado==true){
                    String cadena2 = DefCocol.Complementar_cadena(cadena1, ret22.indice);
                    Retorno_Funcion ret23 = DefCocol.expect("\\}", cadena2);
                    if(ret23.aceptado==true){
                        ret4.aceptado = true;
                        ret4.cadena = ret21.cadena + ret22.cadena + ret23.cadena;
                        ret4.indice = ret21.indice + ret22.indice + ret23.indice;
                        return ret4;
                    }
                }
            }
        //------------------------------------------
        // si hasta ahorita no ha hecho match, ya no puede hacer...
        return new Retorno_Funcion();
    }

    /***********************************************
     * Método: ScannerSP1
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de ScannerSP1
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion ScannerSP1(String cadena) {
        // ScannerSP1 = "CHARACTERS" {SetDecl}

        //------------------------------------------
        // "CHARACTERS"
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.space+"CHARACTERS"+DefCocol.space, cadena);
        if(ret1.aceptado==false){
            Main.Print("No tiene CHARACTERS");
            //No tiene la palabra CHARACTERS
            return new Retorno_Funcion();
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena,ret1.indice);

        //------------------------------------------
        //{SetDecl}
        Retorno_Funcion ret2 = new Retorno_Funcion(0,true,"");
        while(true){
                //------------------------------------------
                // varios espacios en blanco
                Retorno_Funcion espacios = DefCocol.expect(DefCocol.space, cadena1);
                if(espacios.aceptado==true){
                    cadena1 = DefCocol.Complementar_cadena(cadena1,espacios.indice);
                    ret2.indice = ret2.indice+espacios.indice;
                }
            //Main.PrintDB(cadena1);
            //SetDecl
            Retorno_Funcion b = DefCocol.SetDecl(cadena1);
            if(b.aceptado==false){
                //Main.Print("aca termino (no tiene SetDecl)");
                //no hay SetDecl, entonces se sale del *
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret2.indice = ret2.indice+b.indice;
            ret2.cadena = ret2.cadena+b.cadena;
        }

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.indice = ret1.indice + ret2.indice;
        ret.cadena = ret1.cadena + ret2.cadena;
        return ret;
    }

    /***********************************************
     * Método: ScannerSP2
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de ScannerSP2
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion ScannerSP2(String cadena) {
        // ScannerSP1 = "KEYWORDS" {KeywordDecl}

        //------------------------------------------
        // "KEYWORDS"
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.space+"(KEYWORDS)"+DefCocol.space, cadena);
        if(ret1.aceptado==false){
            Main.Print("No tiene KEYWORDS");
            //No tiene la palabra CHARACTERS
            return new Retorno_Funcion();
        }
        //------------------------------------------
        //{KeywordDecl}
        String cadena1 = DefCocol.Complementar_cadena(cadena,ret1.indice);

        Retorno_Funcion ret2 = new Retorno_Funcion(0,true,"");
        while(true){
            //------------------------------------------
                // varios espacios en blanco
                Retorno_Funcion espacios = DefCocol.expect(DefCocol.space, cadena1);
                if(espacios.aceptado==true){
                    cadena1 = DefCocol.Complementar_cadena(cadena1,espacios.indice);
                    ret2.indice = ret2.indice+espacios.indice;
                }
            //Main.PrintDB(cadena1);
            //KeywordDecl
            Retorno_Funcion b = DefCocol.KeywordDecl(cadena1);
            if(b.aceptado==false){
                //Main.Print("aca termino (no tiene KeywordDecl)");
                //no hay KeywordDecl, entonces se sale del *
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret2.indice = ret2.indice+b.indice;
            ret2.cadena = ret2.cadena+b.cadena;
        }

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.indice = ret1.indice + ret2.indice;
        ret.cadena = ret1.cadena + ret2.cadena;
        return ret;
    }

    /***********************************************
     * Método: ScannerSP3
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de ScannerSP3
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion ScannerSP3(String cadena) {
        // ScannerSP1 = "TOKENS" {TokenDecl}

        //------------------------------------------
        // "TOKENS"
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.space+"(TOKENS)"+DefCocol.space, cadena);
        if(ret1.aceptado==false){
            Main.PrintDB("No tiene TOKENS");
            //No tiene la palabra CHARACTERS
            return new Retorno_Funcion();
        }
        //------------------------------------------
        //{TokenDecl}
        String cadena1 = DefCocol.Complementar_cadena(cadena,ret1.indice);

        Retorno_Funcion ret2 = new Retorno_Funcion(0,true,"");
        while(true){
            //------------------------------------------
                // varios espacios en blanco
                Retorno_Funcion espacios = DefCocol.expect(DefCocol.space, cadena1);
                if(espacios.aceptado==true){
                    cadena1 = DefCocol.Complementar_cadena(cadena1,espacios.indice);
                    ret2.indice = ret2.indice+espacios.indice;
                }
            //Main.PrintDB(cadena1);
            //TokenDecl
            Retorno_Funcion b = DefCocol.TokenDecl(cadena1);
            if(b.aceptado==false){
                //Main.Print("aca termino (no tiene TokenDecl)");
                //no hay TokenDecl, entonces se sale del *
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret2.indice = ret2.indice+b.indice;
            ret2.cadena = ret2.cadena+b.cadena;
        }

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.indice = ret1.indice + ret2.indice;
        ret.cadena = ret1.cadena + ret2.cadena;
        return ret;
    }

    /***********************************************
     * Método: Attributes
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de Attributes
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Attributes(String cadena) {
        
        if(cadena.startsWith("<.")==false){
            return (new Retorno_Funcion());
        }
        int indice = cadena.indexOf(".>");
        if(indice == -1){
            return (new Retorno_Funcion());
        }

        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.space, cadena.substring(0, indice+2));

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = cadena.substring(0, indice+2) + ret1.cadena;
        ret.indice = (indice+2) + ret1.indice;
        
        return ret;
        /*
        // Attributes = "<." {ANY} ".>"
        String ANY="([\\w]"+"|"+"[^\\w])*";
        String Attributes="<\\."+"("+ANY+")"+"\\.>";

        //------------------------------------------
        // Attributes
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.space+Attributes+DefCocol.space, cadena);
        if(ret1.aceptado==false){
            return (new Retorno_Funcion());
        }
        return ret1;
         */
    }

    /***********************************************
     * Método: SemAction
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de SemAction
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion SemAction(String cadena) {
        /*
        // SemAction = "(." {ANY} ".)"
        String ANY="([\\w]"+"|"+"[^\\w])*";
        String SemAction="\\(\\."+"("+ANY+")"+"\\.\\)";
         */
        if(cadena.startsWith("(.")==false){
            return (new Retorno_Funcion());
        }
        int indice = cadena.indexOf(".)");
        if(indice == -1){
            return (new Retorno_Funcion());
        }
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.space, cadena.substring(0, indice+2));

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = cadena.substring(0, indice+2) + ret1.cadena;
        ret.indice = (indice+2) + ret1.indice;
        return ret;
        /*
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.space+SemAction+DefCocol.space, cadena);
        if(ret1.aceptado==false){
            return (new Retorno_Funcion());
        }
        return ret1;
         */
    }

    /***********************************************
     * Método: Production
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de Production
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Production(String cadena) {
        // Production = ident [ Attributes ] [ SemAction ] '=' Expression '.'

        //------------------------------------------
        // space
        String cadena1="";
        Retorno_Funcion ret1_1 = DefCocol.expect(DefCocol.space, cadena);
        if(ret1_1.aceptado==true){
            cadena1 = DefCocol.Complementar_cadena(cadena, ret1_1.indice);
        }
        //------------------------------------------
        // ident
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.ident, cadena1);
        if(ret1.aceptado==false){
            Main.PrintDB("TokenDecl no empieza con un ident: "+cadena1);
            return (new Retorno_Funcion());
        }
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret1.indice);
        //------------------------------------------
        // space
        Retorno_Funcion ret1_2 = DefCocol.expect(DefCocol.space, cadena1);
        if(ret1_2.aceptado==true){
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret1_2.indice);
        }
        //------------------------------------------
        //[ Attributes ]
        Retorno_Funcion ret2 = DefCocol.Attributes(cadena1);
        if(ret2.aceptado==true){
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret2.indice);
        }
        else{
            ret2.indice = 0;
            ret2.cadena = "";
        }

        //------------------------------------------
        //[ SemAction ]
        Retorno_Funcion ret3 = DefCocol.SemAction(cadena1);
        if(ret3.aceptado==true){
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret3.indice);
        }
        else{
            ret3.indice = 0;
            ret3.cadena = "";
        }

        //------------------------------------------
        //'='
        Retorno_Funcion ret4 = DefCocol.expect(DefCocol.space+"(=)"+DefCocol.space, cadena1);
        if(ret4.aceptado==false){
            return new Retorno_Funcion();
        }
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret4.indice);

        //------------------------------------------
        // Expression
        Retorno_Funcion ret5 = DefCocol.Expression(cadena1);
        if(ret5.aceptado==false){
            return new Retorno_Funcion();
        }
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret5.indice);

        //------------------------------------------
        // '.'
        Retorno_Funcion ret6 = DefCocol.expect(DefCocol.space+"\\."+DefCocol.space, cadena1);
        if(ret6.aceptado==false){
            return (new Retorno_Funcion());
        }
        Generador_Analizadores.Productions.put(ret1.cadena+ret2.cadena, ret5.cadena);
        //------------------------------------------
        //Si llegó hasta acá, ya fue aceptada
        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1_1.cadena + ret1.cadena + ret1_2.cadena + ret2.cadena + ret3.cadena + ret4.cadena + ret5.cadena + ret6.cadena;
        ret.indice = ret1_1.indice + ret1.indice + ret1_2.indice + ret2.indice + ret3.indice + ret4.indice + ret5.indice + ret6.indice;
        //------------------------------------------
        return ret;
    }

    /***********************************************
     * Método: Expression
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de Expression
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Expression(String cadena) {
        // Expression = Term {'|' Term}
        //------------------------------------------
        // TokenTerm
        Retorno_Funcion ret1 = DefCocol.Term(cadena);
        if(ret1.aceptado==false){
            //ya no puede ser aceptado porque no empieza con un TokenTerm
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);

        //------------------------------------------
        // {'|' Term}
        Retorno_Funcion ret2 = new Retorno_Funcion(0,true,"");
        while(true){
            //Main.PrintDB(cadena1);
            //('|')
            Retorno_Funcion bool = DefCocol.expect(DefCocol.space+"(\\|)"+DefCocol.space, cadena1);
            if(bool.aceptado == false){
                //no tiene '|', entonces se sale del *
                //Main.Print("aca termino (no tiene '|')");
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, bool.indice);
            //TokenTerm
            Retorno_Funcion b = DefCocol.Term(cadena1);
            if(b.aceptado==false){
                //Main.Print("aca termino (no tiene TokenTerm)");
                //no hay BasicSet, entonces se sale del *
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret2.indice = ret2.indice+bool.indice+b.indice;
            ret2.cadena = ret2.cadena+bool.cadena+b.cadena;
        }

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1.cadena+ret2.cadena;
        ret.indice = ret1.indice+ret2.indice;
        return ret;
    }

    /***********************************************
     * Método: Term
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de Term
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Term(String cadena) {
        // Term = Factor { Factor }
        //------------------------------------------
        // Factor
        Retorno_Funcion ret1 = DefCocol.Factor(cadena);
        if(ret1.aceptado==false){
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);

        //------------------------------------------
        // {Factor}
        Retorno_Funcion ret2 = new Retorno_Funcion(0,true,"");
        while(true){
            Retorno_Funcion vacio = DefCocol.expect(DefCocol.space, cadena1);
            if(vacio.aceptado==true){
                cadena1 = DefCocol.Complementar_cadena(cadena1, vacio.indice);
            }
            //Factor
            Retorno_Funcion b = DefCocol.Factor(cadena1);
            if(b.aceptado==false){
                //no hay Factor, entonces se sale del *
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret2.indice = ret2.indice+b.indice + vacio.indice;
            ret2.cadena = ret2.cadena+vacio.cadena+b.cadena ;
        }

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1.cadena+ret2.cadena;
        ret.indice = ret1.indice+ret2.indice;
        return ret;
    }

    /***********************************************
     * Método: Factor
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de Factor
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Factor(String cadena) {
        // Factor = Symbol[Attributes] | '[' Expression ']'| '(' Expression ')'| '{' Expression '}' | SemAction
        //------------------------------------------
        // Factor = Symbol [Attributes]
        Retorno_Funcion ret1 = DefCocol.Symbol(cadena);
        if(ret1.aceptado==true){

            String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);
            //***************************************
            if(DefCocol.expect(DefCocol.string, ret1.cadena).aceptado==true){
                String token = ret1.cadena;
                //revisar si el valor ya estaba entre los tokens
                if(Generador_Analizadores.Tokens_TokenDecl.containsValue(token) == false){
                    Generador_Analizadores.Tokens_TokenDecl.put("Token_Parser"+(contador_token_parsers++), token);
                    tokens_en_parser.add(token);
                    DefCocol.tokens.add(token);
                }

            }
            //***************************************
            Main.PrintDB("Factor es un Symbol");

            Retorno_Funcion ret12 = DefCocol.Attributes(cadena1);
            if(ret12.aceptado==false){
                ret12.indice = 0;
                ret12.cadena = "";
            }

            ret1.indice = ret1.indice + ret12.indice;
            ret1.cadena = ret1.cadena + ret12.cadena;
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            return ret1;
        }
        //------------------------------------------
        // Factor = SemAction
        Retorno_Funcion ret5 = DefCocol.SemAction(cadena);
        if(ret5.aceptado==true){
            return ret5;
        }
        //------------------------------------------
        // Factor = '[' Expression ']'
        Retorno_Funcion ret2 = new Retorno_Funcion();
            Retorno_Funcion ret21 = DefCocol.expect(DefCocol.space+"\\["+DefCocol.space, cadena);
            if(ret21.aceptado==true){
                String cadena1 = DefCocol.Complementar_cadena(cadena, ret21.indice);
                Retorno_Funcion ret22 = DefCocol.Expression(cadena1);
                if(ret22.aceptado==true){
                    String cadena2 = DefCocol.Complementar_cadena(cadena1, ret22.indice);
                    Retorno_Funcion ret23 = DefCocol.expect(DefCocol.space+"\\]"+DefCocol.space, cadena2);
                    if(ret23.aceptado==true){
                        ret2.aceptado = true;
                        ret2.cadena = ret21.cadena + ret22.cadena + ret23.cadena;
                        ret2.indice = ret21.indice + ret22.indice + ret23.indice;
                        return ret2;
                    }
                }
            }

        //------------------------------------------
        // TokenFactor = '(' Expression ')'
        Retorno_Funcion ret3 = new Retorno_Funcion();
            ret21 = DefCocol.expect(DefCocol.space+"\\("+DefCocol.space, cadena);
            if(ret21.aceptado==true){
                String cadena1 = DefCocol.Complementar_cadena(cadena, ret21.indice);
                Retorno_Funcion ret22 = DefCocol.Expression(cadena1);
                if(ret22.aceptado==true){
                    String cadena2 = DefCocol.Complementar_cadena(cadena1, ret22.indice);
                    Retorno_Funcion ret23 = DefCocol.expect(DefCocol.space+"\\)"+DefCocol.space, cadena2);
                    if(ret23.aceptado==true){
                        ret3.aceptado = true;
                        ret3.cadena = ret21.cadena + ret22.cadena + ret23.cadena;
                        ret3.indice = ret21.indice + ret22.indice + ret23.indice;
                        return ret3;
                    }
                }
            }

        //------------------------------------------
        // TokenFactor = '{' Expression '}'
        Retorno_Funcion ret4 = new Retorno_Funcion();
            ret21 = DefCocol.expect(DefCocol.space+"\\{"+DefCocol.space, cadena);
            if(ret21.aceptado==true){
                String cadena1 = DefCocol.Complementar_cadena(cadena, ret21.indice);
                Retorno_Funcion ret22 = DefCocol.Expression(cadena1);
                if(ret22.aceptado==true){
                    String cadena2 = DefCocol.Complementar_cadena(cadena1, ret22.indice);
                    Retorno_Funcion ret23 = DefCocol.expect(DefCocol.space+"\\}"+DefCocol.space, cadena2);
                    if(ret23.aceptado==true){
                        ret4.aceptado = true;
                        ret4.cadena = ret21.cadena + ret22.cadena + ret23.cadena;
                        ret4.indice = ret21.indice + ret22.indice + ret23.indice;
                        return ret4;
                    }
                }
            }
        //------------------------------------------
        // si hasta ahorita no ha hecho match, ya no puede hacer...
        return new Retorno_Funcion();
    }

    /***********************************************
     * Método: ScannerSpecification
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de ScannerSpecification
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion ScannerSpecification(String cadena) {
        // ScannerSpecification = [ScannerSP1][ScannerSP2][ScannerSP3]{WhiteSpaceDecl}
        String cadena1=cadena;
        /*
        Main.PrintDB("\n---------------------------------------------------------------------------------------------\n");
        Main.PrintDB("\n"+cadena1+"\n");
        Main.PrintDB("\n---------------------------------------------------------------------------------------------\n");
         */
        //------------------------------------------
        // [ScannerSP1]
        Retorno_Funcion ret1 = DefCocol.ScannerSP1(cadena1);
        if(ret1.aceptado==true){
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret1.indice);
        }
        else{
            ret1.indice = 0;
        }
        /*
        Main.PrintDB("\n---------------------------------------------------------------------------------------------\n");
        Main.PrintDB("\n"+cadena1+"\n");
        Main.PrintDB("\n---------------------------------------------------------------------------------------------\n");
         */
        //------------------------------------------
        // varios espacios en blanco
        Retorno_Funcion ret2 = DefCocol.expect(DefCocol.space, cadena1);
        if(ret2.aceptado==true){
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret2.indice);
        }
        else{
            ret2.indice = 0;
        }

        //------------------------------------------
        // [ScannerSP2]
        Retorno_Funcion ret3 = DefCocol.ScannerSP2(cadena1);
        if(ret3.aceptado==true){
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret3.indice);
        }
        else{
            ret3.indice = 0;
        }
        
        //------------------------------------------
        // varios espacios en blanco
        Retorno_Funcion ret4 = DefCocol.expect(DefCocol.space, cadena1);
        if(ret4.aceptado==true){
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret4.indice);
        }
        else{
            ret4.indice = 0;
        }

        //------------------------------------------
        // [ScannerSP3]
        Retorno_Funcion ret5 = DefCocol.ScannerSP3(cadena1);
        if(ret5.aceptado==true){
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret5.indice);
        }
        else{
            ret5.indice = 0;
        }

        //------------------------------------------
        //{WhiteSpaceDecl}

        Retorno_Funcion ret6 = new Retorno_Funcion(0,true,"");
        while(true){
            //Main.PrintDB(cadena1);
            //TokenDecl
            Retorno_Funcion b = DefCocol.TokenDecl(cadena1);
            if(b.aceptado==false){
                //Main.Print("aca termino (no tiene TokenDecl)");
                //no hay TokenDecl, entonces se sale del *
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret6.indice = ret6.indice+b.indice;
            ret6.cadena = ret6.cadena+b.cadena;
        }

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.indice = ret1.indice + ret2.indice + ret3.indice + ret4.indice + ret5.indice + ret6.indice;
        ret.cadena = ret1.cadena + ret2.cadena + ret3.cadena + ret4.cadena + ret5.cadena + ret6.cadena;
        return ret;
    }

    /***********************************************
     * Método: ParserSpecification
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de ScannerSpecification
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion ParserSpecification(String cadena) {
        // ParserSpecification = "PRODUCTIONS"
        // Term = Factor { Factor }
        //------------------------------------------
        // "PRODUCTIONS"
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.space+"(PRODUCTIONS)"+DefCocol.space, cadena);
        if(ret1.aceptado==false){
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);

        //------------------------------------------
        // {Production}
        Retorno_Funcion ret2 = new Retorno_Funcion(0,true,"");
        while(true){

            Retorno_Funcion bool = DefCocol.expect(DefCocol.space, cadena1);
            if(bool.aceptado==true){
                cadena1 = DefCocol.Complementar_cadena(cadena1, bool.indice);
                ret2.cadena = ret2.cadena + bool.cadena;
                ret2.indice = ret2.indice + bool.indice;
            }
            //Production
            Retorno_Funcion b = DefCocol.Production(cadena1);
            if(b.aceptado==false){
                //no hay Production, entonces se sale del *
                break;
            }
            cadena1 = DefCocol.Complementar_cadena(cadena1, b.indice);
            ret2.indice = ret2.indice+b.indice;
            ret2.cadena = ret2.cadena+b.cadena;
        }

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.cadena = ret1.cadena+ret2.cadena;
        ret.indice = ret1.indice+ret2.indice;
        return ret;

    }

    /***********************************************
     * Método: Cocol
     * Uso: Revisa si lo ingresado hace match con
     *      toda la sintaxis de Cocol
     * @param cadena
     * @return Retorno_Funcion
    ***********************************************/
    public static Retorno_Funcion Cocol(String cadena) {
        // Cocol = "COMPILER" ident ScannerSpecification ParserSpecification "END" ident '.'

        //------------------------------------------
        // "COMPILER"
        Main.PrintDB("Lo que va a leer para cocol:\n"+cadena);
        Retorno_Funcion ret1 = DefCocol.expect(DefCocol.space+"(COMPILER)"+DefCocol.space, cadena);
        if(ret1.aceptado==false){
            //No empieza con la palabra COMPILER
            DefCocol.error("No contiene la palabra COMPILER");
            return (new Retorno_Funcion());
        }
        String cadena1 = DefCocol.Complementar_cadena(cadena, ret1.indice);
        //Main.PrintDB("########################################################################################");
        //------------------------------------------
        // ident
        Retorno_Funcion ret2 = DefCocol.expect(DefCocol.ident, cadena1);
        if(ret2.aceptado==false){
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            return (new Retorno_Funcion());
        }
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret2.indice);
        Main.PrintDB("########################################################################################");
        //------------------------------------------
        // ScannerSpecification
        Retorno_Funcion ret3 = DefCocol.ScannerSpecification(cadena1);
        if(ret3.aceptado==false){
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            return (new Retorno_Funcion());
        }
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret3.indice);
        Main.PrintDB("########################################################################################");
        //------------------------------------------
        // ParserSpecification
        Retorno_Funcion ret4 = null;
        try{
            Main.PrintDB("si paso: "+cadena1);
            ret4 = DefCocol.ParserSpecification(cadena1);
            if(ret4.aceptado==false){
                //ya no puede ser aceptado porque no empieza con un TokenFactor
                return (new Retorno_Funcion());
            }
            Main.PrintDB("########################################################################################");
            cadena1 = DefCocol.Complementar_cadena(cadena1, ret4.indice);
        }catch(Exception exp){
            Main.Print(exp.getStackTrace().toString());
        }
        //------------------------------------------
        // "END"
        Retorno_Funcion ret5 = DefCocol.expect(DefCocol.space+"(END)"+DefCocol.space, cadena1);
        if(ret5.aceptado==false){
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            DefCocol.error("La definición del compilador no tiene la palabra END");
            return (new Retorno_Funcion());
        }
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret5.indice);

        //------------------------------------------
        // ident
        Retorno_Funcion ret6 = DefCocol.expect(DefCocol.ident, cadena1);
        if(ret6.aceptado==false){
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            return (new Retorno_Funcion());
        }
        //####################################################
        //revision de si ident es igual al inicio que al final
        if(ret6.cadena.compareTo(ret2.cadena)!=0){
            DefCocol.error("Los identificadores del compilador no coinciden");
            return (new Retorno_Funcion());
        }
        Generador_Analizadores.nombre_scanner=ret6.cadena;
        //####################################################
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret6.indice);

        //------------------------------------------
        // '.'
        Retorno_Funcion ret7 = DefCocol.expect(DefCocol.space+"\\."+DefCocol.space, cadena1);
        if(ret7.aceptado==false){
            //ya no puede ser aceptado porque no empieza con un TokenFactor
            DefCocol.error("La definición del compilador no termina en '.'");
            return (new Retorno_Funcion());
        }
        cadena1 = DefCocol.Complementar_cadena(cadena1, ret7.indice);

        Retorno_Funcion ret = new Retorno_Funcion();
        ret.aceptado = true;
        ret.indice = ret1.indice + ret2.indice + ret3.indice + ret4.indice + ret5.indice + ret6.indice + ret7.indice;
        ret.cadena = ret1.cadena + ret2.cadena + ret3.cadena + ret4.cadena + ret5.cadena + ret6.cadena + ret7.cadena;
        return ret;
    }

    /***********************************************
     * Método: error
     * Uso: Se llama cuando hay un error y activa una bandera
     * @param descripcion contiene la descripción del error
    ***********************************************/
    public static void error(String descripcion){
        Main.Print("\n+++---+++---+++---+++---+++---+++---+++---+++---+++---+++\n");
        Main.Print("Descripción: "+descripcion);
        Main.Print("\n+++---+++---+++---+++---+++---+++---+++---+++---+++---+++\n");
    }

}